package com.biz.primus.ms.promotion.dao.po;

import com.biz.primus.base.enums.CommonStatus;
import com.biz.primus.base.enums.PromotionChannelEnum;
import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.base.vo.member.MemberInfoVo;
import com.biz.primus.model.promotion.enums.PromotionProductLimitTypeEnum;
import com.biz.primus.model.promotion.enums.PromotionScopeEnum;
import com.biz.primus.model.promotion.exception.PromotionExceptionType;
import com.biz.primus.model.promotion.vo.OrderPromotionDetailVo;
import com.biz.primus.model.promotion.vo.req.OrderPromotionReqDetailVo;
import com.biz.primus.ms.base.jpa.converter.ListStringConverter;
import com.biz.primus.ms.base.jpa.po.BaseEntity;
import com.google.common.collect.Lists;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * 促销基类
 *
 * @author david-liu
 */
@Entity
@Inheritance
@DiscriminatorColumn(name = "promotion_type")
@Table(name = "pmt_promotion")
@Getter
@Setter
public abstract class BasePromotion extends BaseEntity {
    private static final long serialVersionUID = -3534863181204432632L;

    // 促销名
    @Column(length = 50, nullable = false)
    protected String name;

    // 促销介绍
    @Column(columnDefinition = "TEXT")
    protected String description;

    /**
     * 活动生效的渠道(APP/微商城)
     *
     * @see PromotionChannelEnum
     */
    @Convert(converter = ListStringConverter.class)
    protected List<String> channels;

    // 活动开始时间
    @Column(nullable = false)
    protected LocalDateTime startTime;

    // 活动结束时间
    @Column(nullable = false)
    protected LocalDateTime endTime;

    // 享受活动的会员等级集合
    @Convert(converter = ListStringConverter.class)
    @Column(columnDefinition = "TEXT")
    protected List<Integer> effectMemberLevels;

    // 享受活动的会员标签
    @Convert(converter = ListStringConverter.class)
    @Column(columnDefinition = "TEXT")
    protected List<Long> effectMemberTags;

    // 活动范围
    @Enumerated(value = EnumType.STRING)
    protected PromotionScopeEnum scope;

    /**
     * 活动生效的范围ID集合(活动范围为: 城市 -> 城市ID集合, 店铺 -> 店铺ID集合)
     */
    @Convert(converter = ListStringConverter.class)
    @Column(columnDefinition = "TEXT")
    protected List<Long> scopeIds;

    // 可叠加使用的促销的ID
    @Column(columnDefinition = "TEXT")
    @Convert(converter = ListStringConverter.class)
    protected List<Long> overlayPromotionIds;

    // 促销限制商品限制类型(可选: 按分类, 按品牌, 按商品)
    @Enumerated(value = EnumType.STRING)
    protected PromotionProductLimitTypeEnum productLimitType;

    // 促销限制的商品分类ID
    @Convert(converter = ListStringConverter.class)
    @Column(columnDefinition = "TEXT")
    protected List<Long> limitCategoryIds;

    // 促销限制的商品品牌ID
    @Convert(converter = ListStringConverter.class)
    @Column(columnDefinition = "TEXT")
    protected List<Long> limitBrandIds;

    // 限制的商品ID, 将所有的商品限定条件都要转换成限制商品ID
    @Convert(converter = ListStringConverter.class)
    @Column(columnDefinition = "TEXT")
    protected List<Long> limitProductIds;

    // 是否可以享受折上折(同时使用优惠券和促销)
    @Column(nullable = false)
    protected Boolean allowCoupon = false;

    // 启用状态
    @Enumerated(value = EnumType.STRING)
    protected CommonStatus commonStatus = CommonStatus.ENABLE;

    /**
     * 用户是否只能参加一次
     */
    protected Boolean userOnceGainLimit = false;

    /**
     * 判断当前时间是否在促销的开始时间和结束时间之间
     *
     * @return true: 在; false: 不在
     */
    public boolean isNowInPromotionEffectPeriod() {
        LocalDateTime now = LocalDateTime.now();
        return !Objects.isNull(this.getStartTime()) && !Objects.isNull(this.endTime) && now.isAfter(this.startTime) && now.isBefore(this.endTime);
    }

    /**
     * 判断用户是否在促销范围之内
     *
     * @param memberInfo 用户信息
     * @return true: 在; false: 不在
     */
    public boolean isMemberInPromotionScope(MemberInfoVo memberInfo) {
        boolean isMemberLevelInPromotionScope = !CollectionUtils.isNotEmpty(this.effectMemberLevels) || (Objects.nonNull(memberInfo) && this.effectMemberLevels.contains(memberInfo.getMemberLevel()));
        boolean isMemberTagInPromotionScope = !CollectionUtils.isNotEmpty(this.effectMemberTags) || (Objects.nonNull(memberInfo) && CollectionUtils.intersection(this.getEffectMemberTags(), memberInfo.getMemberTagIds()).size() == memberInfo.getMemberTagIds().size());
        return isMemberLevelInPromotionScope && isMemberTagInPromotionScope;
    }

    /**
     * 判断促销是否满足商品的限制
     *
     * @param detailVo 订单促销请求详情Vo
     * @return boolean
     */
    public boolean isProductInPromotionLimit(OrderPromotionReqDetailVo detailVo) {
        detailVo.postProcess();
        if (Objects.isNull(this.getProductLimitType())) {
            return true;
        } else {
            if (this.getProductLimitType() == PromotionProductLimitTypeEnum.LIMIT_BY_CATEGORY) {
                return CollectionUtils.intersection(this.getLimitCategoryIds(), detailVo.getRequestCategoryIds()).size() > 0;
            } else if (this.getProductLimitType() == PromotionProductLimitTypeEnum.LIMIT_BY_BRAND) {
                return CollectionUtils.intersection(this.getLimitBrandIds(), detailVo.getRequestBrandIds()).size() > 0;
            } else {
                return CollectionUtils.intersection(this.getLimitProductIds(), detailVo.getRequestProductIds()).size() > 0;
            }
        }
    }

    /**
     * 判断是否满足促销的具体的规则
     *
     * @param detailVo 订单商品详情Vo
     * @return boolean
     */
    public abstract boolean isMatchPromotionRule(OrderPromotionReqDetailVo detailVo);

    /**
     * 获取订单商品促销详情
     *
     * @param reqDetailVo 订单商品详情Vo
     * @return 促销详情
     */
    public abstract OrderPromotionDetailVo getOrderPromotionDetail(OrderPromotionReqDetailVo reqDetailVo);

    /**
     * 获取受促销影响的商品ID
     *
     * @param reqDetailVo 订单商品详情Vo
     * @return 商品ID集合
     */
    public List<Long> getPromotionEffectProductIds(OrderPromotionReqDetailVo reqDetailVo) {
        AssertUtils.isTrue(Objects.nonNull(reqDetailVo), PromotionExceptionType.ILLEGAL_PARAMETER);
        reqDetailVo.postProcess();
        if (!this.isProductInPromotionLimit(reqDetailVo)) {
            return Collections.emptyList();
        }
        if (Objects.isNull(this.productLimitType)) {
            return reqDetailVo.getRequestProductIds();
        } else {
            final List<Long> effectProductIds = Lists.newArrayList();
            if (this.productLimitType == PromotionProductLimitTypeEnum.LIMIT_BY_CATEGORY) {
                for (Object o : CollectionUtils.intersection(this.getLimitCategoryIds(), reqDetailVo.getRequestCategoryIds())) {
                    Long categoryId = (Long) o;
                    effectProductIds.addAll(reqDetailVo.getRequestCategoryProductIds(categoryId));
                }
            } else if (this.productLimitType == PromotionProductLimitTypeEnum.LIMIT_BY_BRAND) {
                for (Object o : CollectionUtils.intersection(this.getLimitBrandIds(), reqDetailVo.getRequestBrandIds())) {
                    Long brandId = (Long) o;
                    effectProductIds.addAll(reqDetailVo.getRequestBrandProductIds(brandId));
                }
            } else {
                for (Object o : CollectionUtils.intersection(this.getLimitProductIds(), reqDetailVo.getRequestProductIds())) {
                    effectProductIds.add((Long) o);
                }
            }
            return effectProductIds;
        }
    }

    public List<String> getEffectMemberLevelStringList() {
        List<String> memberLevels = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(this.effectMemberLevels)) {
            for (int i = 0; i < this.effectMemberLevels.size(); i++) {
                memberLevels.add(String.valueOf(this.effectMemberLevels.get(i)));
            }
        }
        return memberLevels;

    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }
}
